#include "FileManager.h"
#include <filesystem>
#include <iostream>
#include <cstring>
#include <sys/stat.h>
#include <vector> // 添加这行
namespace fs = std::filesystem;

namespace MiniDB
{

    // FileHandle 实现
    FileHandle::FileHandle(const std::string &filename)
        : filename_(filename), is_open_(false)
    {
        file_.open(filename, std::ios::in | std::ios::out | std::ios::binary);
        if (file_.is_open())
        {
            is_open_ = true;
        }
        else
        {
            // 文件不存在，创建新文件
            file_.open(filename, std::ios::out | std::ios::binary);
            if (file_.is_open())
            {
                file_.close();
                file_.open(filename, std::ios::in | std::ios::out | std::ios::binary);
                is_open_ = file_.is_open();
            }
        }
    }

    FileHandle::~FileHandle()
    {
        if (is_open_)
        {
            file_.close();
        }
    }

    FileHandle::FileHandle(FileHandle &&other) noexcept
        : filename_(std::move(other.filename_)),
          file_(std::move(other.file_)),
          is_open_(other.is_open_)
    {
        other.is_open_ = false;
    }

    FileHandle &FileHandle::operator=(FileHandle &&other) noexcept
    {
        if (this != &other)
        {
            if (is_open_)
            {
                file_.close();
            }
            filename_ = std::move(other.filename_);
            file_ = std::move(other.file_);
            is_open_ = other.is_open_;
            other.is_open_ = false;
        }
        return *this;
    }

    bool FileHandle::readBlock(int block_id, char *buffer, size_t block_size)
    {
        if (!is_open_)
            return false;

        file_.seekg(block_id * block_size, std::ios::beg);
        if (file_.fail())
            return false;

        file_.read(buffer, block_size);
        return !file_.fail();
    }

    bool FileHandle::writeBlock(int block_id, const char *buffer, size_t block_size)
    {
        if (!is_open_)
        {
            std::cout << "FileHandle::writeBlock: File not open" << std::endl;
            return false;
        }

        size_t position = block_id * block_size;
        std::cout << "FileHandle::writeBlock: Writing block " << block_id
                  << " at position " << position << std::endl;

        // Always try to seek to the position first
        std::cout << "FileHandle::writeBlock: Attempting seek to position " << position << std::endl;
        file_.seekp(position, std::ios::beg);
        if (file_.fail())
        {
            std::cout << "FileHandle::writeBlock: Direct seek failed, extending file..." << std::endl;
            file_.clear();

            // Get current file size
            file_.seekp(0, std::ios::end);
            size_t current_size = file_.tellp();
            std::cout << "FileHandle::writeBlock: Current file size: " << current_size << std::endl;

            // If we need to extend the file
            if (position > current_size)
            {
                std::cout << "FileHandle::writeBlock: Need to extend file by " << (position - current_size) << " bytes" << std::endl;

                // Move back to end and write zeros to reach the desired position
                file_.seekp(0, std::ios::end);
                size_t bytes_to_add = position - current_size;
                std::vector<char> padding(bytes_to_add, 0);
                std::cout << "FileHandle::writeBlock: Writing " << padding.size() << " padding bytes" << std::endl;
                file_.write(padding.data(), padding.size());

                if (file_.fail())
                {
                    std::cout << "FileHandle::writeBlock: Failed to extend file" << std::endl;
                    file_.clear();
                    return false;
                }

                std::cout << "FileHandle::writeBlock: File extended successfully" << std::endl;
            }

            // Now try to seek to the position again
            std::cout << "FileHandle::writeBlock: Retrying seek to position " << position << std::endl;
            file_.seekp(position, std::ios::beg);
            if (file_.fail())
            {
                std::cout << "FileHandle::writeBlock: Seek failed after extending file" << std::endl;
                file_.clear();
                return false;
            }

            std::cout << "FileHandle::writeBlock: Seek successful after extending file" << std::endl;
        }
        else
        {
            std::cout << "FileHandle::writeBlock: Direct seek successful" << std::endl;
        }

        // Write the actual data
        file_.write(buffer, block_size);
        if (file_.fail())
        {
            std::cout << "FileHandle::writeBlock: Write failed for block " << block_id << std::endl;
            file_.clear();
            return false;
        }

        // Ensure data is written to disk
        file_.flush();

        std::cout << "FileHandle::writeBlock: Successfully wrote block " << block_id << std::endl;
        return true;
    }

    bool FileHandle::appendBlock(const char *buffer, size_t block_size)
    {
        if (!is_open_)
            return false;

        file_.seekp(0, std::ios::end);
        file_.write(buffer, block_size);
        return !file_.fail();
    }

    int FileHandle::getBlockCount()
    {
        if (!is_open_)
            return 0;

        auto current_pos = file_.tellg();
        file_.seekg(0, std::ios::end);
        auto end_pos = file_.tellg();
        file_.seekg(current_pos);

        size_t file_size = static_cast<size_t>(end_pos);
        return (file_size + 4095) / 4096; // 向上取整
    }

    size_t FileHandle::getFileSize()
    {
        if (!is_open_)
            return 0;

        struct stat stat_buf;
        if (stat(filename_.c_str(), &stat_buf) == 0)
        {
            return static_cast<size_t>(stat_buf.st_size);
        }

        // 备选方案：使用文件流
        auto current_pos = file_.tellg();
        file_.seekg(0, std::ios::end);
        auto end_pos = file_.tellg();
        file_.seekg(current_pos);

        if (end_pos >= 0)
        {
            return static_cast<size_t>(end_pos);
        }

        return 0;
    }

    bool FileHandle::isOpen() const
    {
        return is_open_;
    }

    void FileHandle::flush()
    {
        if (is_open_)
        {
            file_.flush();
        }
    }

    // FileManager 实现
    FileManager &FileManager::getInstance()
    {
        static FileManager instance;
        return instance;
    }

    std::shared_ptr<FileHandle> FileManager::createFile(const std::string &filename)
    {
        if (open_files_.find(filename) != open_files_.end())
        {
            return open_files_[filename];
        }

        auto file_handle = std::make_shared<FileHandle>(filename);
        if (file_handle->isOpen())
        {
            open_files_[filename] = file_handle;
            return file_handle;
        }

        return nullptr;
    }

    std::shared_ptr<FileHandle> FileManager::openFile(const std::string &filename)
    {
        if (open_files_.find(filename) != open_files_.end())
        {
            return open_files_[filename];
        }

        if (!fileExists(filename))
        {
            return nullptr;
        }

        auto file_handle = std::make_shared<FileHandle>(filename);
        if (file_handle->isOpen())
        {
            open_files_[filename] = file_handle;
            return file_handle;
        }

        return nullptr;
    }

    void FileManager::closeFile(const std::string &filename)
    {
        auto it = open_files_.find(filename);
        if (it != open_files_.end())
        {
            it->second->flush();
            open_files_.erase(it);
        }
    }

    bool FileManager::deleteFile(const std::string &filename)
    {
        closeFile(filename);

        std::error_code ec;
        return fs::remove(filename, ec);
    }

    bool FileManager::fileExists(const std::string &filename)
    {
        return fs::exists(filename);
    }

    void FileManager::createDirectory(const std::string &dirname)
    {
        std::error_code ec;
        fs::create_directories(dirname, ec);
    }

    bool FileManager::directoryExists(const std::string &dirname)
    {
        return fs::exists(dirname) && fs::is_directory(dirname);
    }

} // namespace MiniDB
